package com.mgface.metadata.design.config;

import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.mgface.metadata.design.udd.UDDEngine;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Iterator;
import java.util.Properties;

/**
 * 1 * 告诉MyBatis当前插件用来拦截哪个对象的哪个方法
 * 2 * type:要拦截的四大类型
 * 3 * method：拦截那个方法
 * 4 * args：这个方法的入参
 */

@Intercepts(
        {
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        }
)
@Slf4j
@Component
public class MybatisSqlInterceptor implements Interceptor {
    @Autowired
    private UDDEngine uddEngine;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        Object[] args = invocation.getArgs();
        if (target instanceof Executor) {
            Executor executor = (Executor) target;
            MappedStatement ms = (MappedStatement) args[0];
            if (ms.getSqlCommandType() == SqlCommandType.SELECT) {
                Object parameter = args[1];
                RowBounds rowBounds = (RowBounds) args[2];
                ResultHandler resultHandler = (ResultHandler) args[3];
                CacheKey cacheKey;
                BoundSql boundSql;
                //由于逻辑关系，只会进入一次
                if (args.length == 4) {
                    //4 个参数时
                    boundSql = ms.getBoundSql(parameter);
                    cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
                } else {
                    //6 个参数时
                    cacheKey = (CacheKey) args[4];
                    boundSql = (BoundSql) args[5];
                }
                //TODO 自己要进行的各种处理
                String sql = boundSql.getSql();
                Field sqlField = boundSql.getClass().getDeclaredField("sql");
                sqlField.setAccessible(true);
                log.info("执行SQL：{}", sql);
                //SQL转换
                //在这里执行UDD处理
                sql = uddEngine.exec(sql);
                //设置解析后的表处理
                sqlField.set(boundSql, sql);

                //这里执行分页处理
//                Iterator var11 = this.interceptors.iterator();
//
//                while(var11.hasNext()) {
//                    InnerInterceptor query = (InnerInterceptor)var11.next();
//                    if (!query.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql)) {
//                        return Collections.emptyList();
//                    }
//
//                    query.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
//                }

                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
                return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
            }
        } else {

        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return target instanceof Executor ? Plugin.wrap(target, this) : target;
    }

    @Override
    public void setProperties(Properties properties) {
    }

}
